package net.sourceforge.peers.sip.core.useragent;

import net.sourceforge.peers.Logger;
import net.sourceforge.peers.sip.RFC3261;
import net.sourceforge.peers.sip.Utils;
import net.sourceforge.peers.sip.core.useragent.handlers.ByeHandler;
import net.sourceforge.peers.sip.core.useragent.handlers.CancelHandler;
import net.sourceforge.peers.sip.core.useragent.handlers.InviteHandler;
import net.sourceforge.peers.sip.core.useragent.handlers.OptionsHandler;
import net.sourceforge.peers.sip.core.useragent.handlers.RegisterHandler;
import net.sourceforge.peers.sip.syntaxencoding.NameAddress;
import net.sourceforge.peers.sip.syntaxencoding.SipHeaderFieldName;
import net.sourceforge.peers.sip.syntaxencoding.SipHeaderFieldValue;
import net.sourceforge.peers.sip.syntaxencoding.SipHeaderParamName;
import net.sourceforge.peers.sip.syntaxencoding.SipHeaders;
import net.sourceforge.peers.sip.syntaxencoding.SipURI;
import net.sourceforge.peers.sip.syntaxencoding.SipUriSyntaxException;
import net.sourceforge.peers.sip.transaction.ClientTransaction;
import net.sourceforge.peers.sip.transaction.ServerTransaction;
import net.sourceforge.peers.sip.transaction.ServerTransactionUser;
import net.sourceforge.peers.sip.transaction.TransactionManager;
import net.sourceforge.peers.sip.transactionuser.DialogManager;
import net.sourceforge.peers.sip.transport.SipRequest;
import net.sourceforge.peers.sip.transport.SipResponse;
import net.sourceforge.peers.sip.transport.TransportManager;

/**
 * 初始请求处理器
 * @author Mr.Yan
 */
public class InitialRequestManager extends RequestManager
        implements ServerTransactionUser {

    public InitialRequestManager(UserAgent userAgent,
            InviteHandler inviteHandler,
            CancelHandler cancelHandler,
            ByeHandler byeHandler,
            OptionsHandler optionsHandler,
            RegisterHandler registerHandler,
            DialogManager dialogManager,
            TransactionManager transactionManager,
            TransportManager transportManager,
            Logger logger) {
        super(userAgent,
                inviteHandler,
                cancelHandler,
                byeHandler,
                optionsHandler,
                registerHandler,
                dialogManager,
                transactionManager,
                transportManager,
                logger);
        registerHandler.setInitialRequestManager(this);
    }

    /**
     *组装通用请求头
     * @param requestUri sip:124.223.170.227
     * @param method  REGISTER  INVITE ...
     * @param profileUri  sip:103@124.223.170.227
     * @param callId 会话标识id
     * @param fromTag 请求发起者显示名称
     * @return  构造好的request请求
     */
    public SipRequest getGenericRequest(String requestUri, String method,
            String profileUri, String callId, String fromTag)
            throws SipUriSyntaxException {
        //SIP 请求的起始行有 Request-Line，作为与其它消息的区分。Request-Line 包含一个方法名、一个 Request-URI 和由空格（SP）字符分开的协议版本
        SipRequest request = new SipRequest(method, new SipURI(requestUri));

        //请求头组装
        SipHeaders headers = request.getSipHeaders();

        //Max-Forwards
        Utils.addCommonHeaders(headers);

        //to
        NameAddress to = new NameAddress(requestUri);
        headers.add(new SipHeaderFieldName(RFC3261.HDR_TO),
                new SipHeaderFieldValue(to.toString()));
        
        //From
        NameAddress fromNA = new NameAddress(profileUri);
        SipHeaderFieldValue from = new SipHeaderFieldValue(fromNA.toString());
        String localFromTag;
        if (fromTag != null) {
            localFromTag = fromTag;
        } else {
            localFromTag = Utils.generateTag();
        }
        from.addParam(new SipHeaderParamName(RFC3261.PARAM_TAG), localFromTag);
        headers.add(new SipHeaderFieldName(RFC3261.HDR_FROM), from);
        
        //Call-ID
        
        SipHeaderFieldName callIdName =
            new SipHeaderFieldName(RFC3261.HDR_CALLID);
        String localCallId;
        if (callId != null) {
            localCallId = callId;
        } else {
            localCallId = Utils.generateCallID(
                    userAgent.getConfig().getLocalInetAddress());
        }
        headers.add(callIdName, new SipHeaderFieldValue(localCallId));
        
        //CSeq
        headers.add(new SipHeaderFieldName(RFC3261.HDR_CSEQ),
                new SipHeaderFieldValue(userAgent.generateCSeq(method)));
        
        return request;
    }

    /**
     * 创建初始请求
     * @param requestUri  请求URI
     * @param method   请求方法
     * @param profileUri  完整URI
     * @param callId  会话标识
     */
    public SipRequest createInitialRequest(String requestUri, String method,
            String profileUri, String callId) throws SipUriSyntaxException {
        
        return createInitialRequest(requestUri, method, profileUri, callId,
                null, null);
    }
    
    public SipRequest createInitialRequest(String requestUri, String method,
            String profileUri, String callId, String fromTag,
            MessageInterceptor messageInterceptor)
                throws SipUriSyntaxException {

        //组装基本请求头
        SipRequest sipRequest = getGenericRequest(requestUri, method,
                profileUri, callId, fromTag);
        

        //组装出站代理
        SipURI outboundProxy = userAgent.getOutboundProxy();
        if (outboundProxy != null) {
            NameAddress outboundProxyNameAddress =
                new NameAddress(outboundProxy.toString());
            sipRequest.getSipHeaders().add(new SipHeaderFieldName(RFC3261.HDR_ROUTE),
                    new SipHeaderFieldValue(outboundProxyNameAddress.toString()), 0);
        }


        ClientTransaction clientTransaction = null;

        //判断方法类型
        if (RFC3261.METHOD_INVITE.equals(method)) {
            clientTransaction = inviteHandler.preProcessInvite(sipRequest);
        } else if (RFC3261.METHOD_REGISTER.equals(method)) {
            clientTransaction = registerHandler.preProcessRegister(sipRequest);
        }

        //发送消息
        createInitialRequestEnd(sipRequest, clientTransaction, profileUri, messageInterceptor, true);
        return sipRequest;
    }
    
    private void createInitialRequestEnd(SipRequest sipRequest,
            ClientTransaction clientTransaction, String profileUri,
            MessageInterceptor messageInterceptor, boolean addContact) {
    	if (clientTransaction == null) {
    		logger.error("method not supported");
    		return;
    	}

        //添加Contact请求头
    	if (addContact) {
    	    addContact(sipRequest, clientTransaction.getContact(), profileUri);
    	}

        if (messageInterceptor != null) {
            messageInterceptor.postProcess(sipRequest);
        }

        clientTransaction.start();
    }
    
    public void createCancel(SipRequest inviteRequest,
            MidDialogRequestManager midDialogRequestManager, String profileUri) {
        SipHeaders inviteHeaders = inviteRequest.getSipHeaders();
        SipHeaderFieldValue callId = inviteHeaders.get(
                new SipHeaderFieldName(RFC3261.HDR_CALLID));
        SipRequest sipRequest;
        try {
            sipRequest = getGenericRequest(
                    inviteRequest.getRequestUri().toString(), RFC3261.METHOD_CANCEL,
                    profileUri, callId.getValue(), null);
        } catch (SipUriSyntaxException e) {
            logger.error("syntax error", e);
            return;
        }
        
        ClientTransaction clientTransaction;
            clientTransaction = cancelHandler.preProcessCancel(sipRequest,
                    inviteRequest, midDialogRequestManager);
        if (clientTransaction != null) {
            createInitialRequestEnd(sipRequest, clientTransaction, profileUri,
                    null, false);
        }
        
        
    }

    public void manageInitialRequest(SipRequest sipRequest) {
        SipHeaders headers = sipRequest.getSipHeaders();
        
        //authentication
        
        //method inspection
        SipResponse sipResponse = null;
        //不支持此方法  返回405状态码  且返回的响应里必须包含支持的请求类型
        if (!UAS.SUPPORTED_METHODS.contains(sipRequest.getMethod())) {
            // generate 405  with Allow header
            //(20.5) and send it
            sipResponse = generateResponse(sipRequest, null,
                    RFC3261.CODE_405_METHOD_NOT_ALLOWED,
                    RFC3261.REASON_405_METHOD_NOT_ALLOWED);
            SipHeaders sipHeaders = sipResponse.getSipHeaders();
            sipHeaders.add(new SipHeaderFieldName(RFC3261.HDR_ALLOW),
                    new SipHeaderFieldValue(Utils.generateAllowHeader()));
        }

        
        SipHeaderFieldValue contentType =
            headers.get(new SipHeaderFieldName(RFC3261.HDR_CONTENT_TYPE));
        // generate 415 with a Accept header listing supported content types


        //if语句成立说明 请求不支持 直接返回
        if (sipResponse != null) {
            ServerTransaction serverTransaction =
                transactionManager.createServerTransaction(
                    sipResponse, userAgent.getSipPort(), RFC3261.TRANSPORT_UDP,
                    this, sipRequest);
            serverTransaction.start();
            serverTransaction.receivedRequest(sipRequest);
            serverTransaction.sendReponse(sipResponse);
        }
        
        //对话外的请求的类型判别
        String method = sipRequest.getMethod();
        if (RFC3261.METHOD_INVITE.equals(method)) {
            inviteHandler.handleInitialInvite(sipRequest);
        } else if (RFC3261.METHOD_CANCEL.equals(method)) {
            cancelHandler.handleCancel(sipRequest);
        } else if (RFC3261.METHOD_OPTIONS.equals(method)) {
            optionsHandler.handleOptions(sipRequest);
        }
    }

    public void addContact(SipRequest sipRequest, String contactEnd,
            String profileUri) {
        SipHeaders sipHeaders = sipRequest.getSipHeaders();

        //sipRequest添加Contact
        StringBuilder contactBuf = new StringBuilder();
        contactBuf.append(RFC3261.SIP_SCHEME);
        contactBuf.append(RFC3261.SCHEME_SEPARATOR);
        String userPart = Utils.getUserPart(profileUri);
        contactBuf.append(userPart);
        contactBuf.append(RFC3261.AT);
        contactBuf.append(contactEnd);

        NameAddress contactNA = new NameAddress(contactBuf.toString());
        SipHeaderFieldValue contact = new SipHeaderFieldValue(contactNA.toString());
        sipHeaders.add(new SipHeaderFieldName(RFC3261.HDR_CONTACT), new SipHeaderFieldValue(contact.toString()));
    }

    ///////////////////////////////////////////////////////////
    // ServerTransactionUser methods
    ///////////////////////////////////////////////////////////

    @Override
    public void transactionFailure() {

    }

}
